1 /*
2 * Title: S/MIME Project
3 * Description: S/MIME email sending capabilities
4 * @Author Vladan Obradovic
5 * @Version 2.0.1
6 */
7
8 package org.webdocwf.util.smime.smime;
9
10
11 import org.webdocwf.util.smime.exception.SMIMEException;
12 import org.webdocwf.util.smime.exception.ErrorStorage;
13 import org.webdocwf.util.smime.activation.CMSSignedDataSource;
14 import org.webdocwf.util.smime.mail.MultipartGenerator;
15 import org.webdocwf.util.smime.util.ConvertAssist;
16 import org.webdocwf.util.smime.activation.StreamDataSource;
17 import javax.mail.Session;
18 import javax.mail.Message;
19 import javax.mail.Multipart;
20 import javax.mail.Transport;
21 import javax.mail.MessagingException;
22 import javax.mail.internet.HeadersUtil;
23 import javax.mail.internet.MimeMessage;
24 import javax.mail.internet.MimeBodyPart;
25 import javax.mail.internet.MimeMultipart;
26 import javax.mail.internet.InternetAddress;
27 import javax.activation.DataHandler;
28 import javax.activation.FileDataSource;
29 import javax.activation.MimetypesFileTypeMap;
30 import java.util.Vector;
31 import java.util.Properties;
32 import java.util.SimpleTimeZone;
33 import java.util.GregorianCalendar;
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.InputStream;
37 import java.io.ByteArrayInputStream;
38 import java.security.Security;
39 import java.security.KeyStoreException;
40 import java.security.PrivateKey;
41 import java.security.KeyStore;
42 import java.security.cert.X509Certificate;
43 import java.security.cert.CertificateFactory;
44 import java.security.cert.CertificateException;
45 import sun.security.provider.Sun;
46 import org.bouncycastle.jce.provider.BouncyCastleProvider;
47
48
49 /***
50 * SignedSMIME class is used for creating and sending signed S/MIME message.<BR>
51 * <BR>
52 * Email message is in general composed of the content of the message and of one or
53 * more attachments. The content is visible part of the message, and attacments are
54 * mostly files or other binary data, which are not visible parts of message and
55 * which are used by email as a transport medium. In this implementation content
56 * can be represented in two different forms: <BR>
57 * <BR>
58 * <UL><LI>
59 * text/plain (only text withouth any formating) or
60 * </LI> <LI>
61 * text/html (html coded view of message)
62 * </LI></UL>
63 * Also, content can be absent, but than at least one attachment must be added.
64 * Content can be set on few manners. For text/plain type it can be done in time
65 * of construction with constructor designed special for creation of text/plain
66 * messages. Also, text content can be created by any of setContent() methods,
67 * if construction of object was done by other constructor which create object
68 * with empty content. Construction with other constructor offers a few different
69 * posibilities for importing content data (File, InputStream, String) by using
70 * appropriate setContent() method. If method with four parameters is used, 3rd
71 * ant 4th parameters are not in use for text/plain message and could be set
72 * null. For setting text/html content, construction of object should be done
73 * only by second mentioned constructor, which creates object with empty content.
74 * Content should be populated by html code with setContent() method. 3rd
75 * parameter is used for resolving relative addresses of resources in html
76 * code (images, movies...) and 4th parameter serves as data source for resources
77 * that are on special way addressed in html code. Also, there is a setContent()
78 * method which doesn't care about resources and which creates message content
79 * withouth them. For more information refer to setContent() methods.<BR>
80 * <BR>
81 * Message can contain any number of attachments. Also, message can
82 * be wihouth any attachment, but then content must be present. Every attachment
83 * should be added by performing single addAttachment() method. Attachments
84 * can be added from file or from InputStream. Mime-type which corresponds to
85 * particular attachment is obtained according to extension of file name
86 * (virtual or real file name) passed to addAttachment() method. File mime.types
87 * in META_INF directory contains list of mime-types and corresponding extensions
88 * which are used in determination of mime-type. File can be changed to satisfy
89 * secific requrements. For more information refer to addAttachmenttent()
90 * method.<BR>
91 * <BR>
92 * Message can be external (explicit) or internal (implicit) signed. External
93 * signing allows email receiving clients wihouth implemented SMIME
94 * capabilities to preview the signed SMIME email messages.<BR>
95 * <BR>
96 * Message can be signed with or without Signed Attributes. Signed Attributes
97 * are one optional part of CMS (Cryptographic Message Syntax) signed objects,
98 * and consist of some atributes used in the process of signing (date and time
99 * of signing, capabilities of sending email client, message digest value...).
100 * If those attributes are ommited, only pure message is taken in the process
101 * of signing.<BR>
102 * <BR>
103 * Digest algorithm can be SHA1, MD2 or MD5 which depends on selected signing algorithm.<BR>
104 * <BR>
105 * Capabilities Attributes are one of Signed Attributes, and in the process of
106 * signing (if Signed Attributes are involved) can be set. This attributes
107 * indicate to recipient email client which encipher, symmetric and/or signature
108 * algorithms signer's email client preferes, and they can be used in the next
109 * communication between each others. Setting this posibilities is optional, but
110 * if it is set, order of adding gives the information about most preferes algorithms
111 * within paricular group of algorithms. Defined Capabilities Attributes in this version
112 * of Signed SMIME can be from group: RC2 40, RC2 64, RC2 128, DES and DES_EDE3 for
113 * symmetric encryption algorihms, from group: MD2 with RSA, MD5 with RSA, SHA1 with RSA
114 * and SHA1 with DSA for signing algorithms, and RSA for encipher algorithm. For more
115 * information see setCapabilities method in this class.<BR>
116 * <BR>
117 * Certificates of signers and their root authorities can be included in the
118 * signed message. This posibilities allow the recipient of signed SMIME
119 * message to automatically include signer's certificates as trusted, and verify
120 * signed message. This posibilities are optional.<BR>
121 * <BR>
122 * More than one signer can perform signing of message and they can use
123 * different signing algorithms. Digital signing can be performed by SHA1_WITH_RSA,
124 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA.<BR>
125 * <BR>
126 */
127 public class SignedSMIME {
128
129 /***
130 * Container for MIME message
131 */
132 private MimeMessage message;
133
134 /***
135 * Storage for .pfx files corresponding to appropriate signing session (used
136 * for first type of addSigner function).
137 */
138 private Vector ksArray = new Vector(0, 1);
139
140 /***
141 * Storage for digest algorithm corresponding to appropriate signing session
142 * (used for first type of addSigner function).
143 */
144 private Vector digestArray = new Vector(0, 1);
145
146 /***
147 * Storage for byte[2] grouped indicators (used for first type of addSigner
148 * function).
149 */
150 private Vector including = new Vector(0, 1);
151
152 /***
153 * Storage for certificate chain corresponding to appropriate signing session
154 * (used for second type of addSigner function)
155 */
156 private Vector certChainArray = new Vector(0, 1);
157
158 /***
159 * Storage for private key corresponding to appropriate signing session (used
160 * for second type of addSigner function)
161 */
162 private Vector privKeyArray = new Vector(0, 1);
163
164 /***
165 * Storage for digest algorithm corresponding to appropriate signing session
166 * (used for second type of addSigner function)
167 */
168 private Vector digestArray2 = new Vector(0, 1);
169
170 /***
171 * Storage for byte[2] grouped indicators (used for second type of addSigner
172 * function)
173 */
174 private Vector including2 = new Vector(0, 1);
175
176 /***
177 * Storage for MIME bodyparts
178 */
179 private Vector bodyPartArray = new Vector(0, 1);
180
181 /***
182 * Storage for additional certificates
183 */
184 private Vector aditionalCerts = new Vector(0, 1);
185
186 /***
187 * Temporary storage for capabilities (after method addSigner, this object is
188 * copied to capabilities or capabilities2)
189 */
190 private Vector capabilitiesTemp = new Vector(0, 1);
191
192 /***
193 * Storage for capabilities (used for first type of addSigner function)
194 */
195 private Vector capabilities = new Vector(0, 1);
196
197 /***
198 * Storage for capabilities (used for second type of addSigner function)
199 */
200 private Vector capabilities2 = new Vector(0, 1);
201
202 /***
203 * Indication that at least one recipient must be TO (others may be CC or BCC)
204 */
205 private boolean indicatorTo = false;
206
207 /***
208 * Indicator of the presence of plain text content
209 */
210 private boolean textContentPresence = false;
211
212 /***
213 * Initializes the JavaMail session for SMTP and MimeMessage for signing.
214 * Dynamically loads the BC and SUN provider necessary for encryption. This
215 * constructor is used for creating message with text/plain content. For creating
216 * html formated content (text/html) other constructor should be used in
217 * combination with one of the setContent methods. Note that after using this
218 * constructor setContent method can be used only if "content" argument of
219 * constructor was given as null, otherwise setContent method can't be used
220 * because content is already set as text/plain.
221 * @param smtpHost name of SMTP host used for sending email
222 * @param fromAddress email address of sender (FROM field in email header)
223 * @param subject subject of email (SUBJECT field in email header)
224 * @param content text/plain content of email message
225 * @exception SMIMEException if smtpHost or fromAddress parameters are null.
226 * Also, it can be caused by non SMIMEException which is MessagingException.
227 */
228 public SignedSMIME(String smtpHost, String fromAddress, String subject,
229 String content) throws SMIMEException {
230 try {
231 Security.addProvider(new BouncyCastleProvider()); // Dynamic loading the BC provider
232 Security.addProvider(new Sun()); // Dynamic loading the SUN provider necessary for SHA1withRSA
233
234 if (smtpHost == null | fromAddress == null)
235 throw new SMIMEException(this, 1041);
236 Properties sesProp = new Properties();
237
238 sesProp.setProperty("mail.smtp.host", smtpHost);
239 Session ses = Session.getInstance(sesProp);
240
241 message = new MimeMessage(ses);
242 InternetAddress from = new InternetAddress(fromAddress);
243
244 message.setFrom(from);
245 if (subject != null)
246 message.setSubject(subject);
247 if (content != null) {
248 MimeBodyPart mbp = new MimeBodyPart();
249
250 mbp.setText(content);
251 bodyPartArray.addElement(mbp);
252 textContentPresence = true;
253 }
254 } catch (Exception e) {
255 throw SMIMEException.getInstance(this, e, "constructor");
256 }
257 }
258
259 /***
260 * Initializes the JavaMail session for SMTP and MimeMessage for signing.
261 * Dynamically loads the BC and SUN provider necessary for encryption. This
262 * constructor does not create content of message and it can be set later with
263 * one of setContent methods. Also, message can be left withouth content, but
264 * then at least one attachement must be added.
265 * @param smtpHost name of SMTP host used for sending email
266 * @param fromAddress email address of sender (FROM field in email header)
267 * @param subject subject of email (SUBJECT field in email header)
268 * @exception SMIMEException if smtpHost or fromAddress parameters are null.
269 * Also, it can be caused by non SMIMEException which is MessagingException.
270 */
271 public SignedSMIME(String smtpHost, String fromAddress, String subject)
272 throws SMIMEException {
273 this(smtpHost, fromAddress, subject, null);
274 }
275
276 /***
277 * Sets message content. Message content can be given in two differrent forms:
278 * text and html code. If content is type of text, parameter "type" should be
279 * "text/plain" and other two parameters are not in use (should be set null).
280 * If content is type of html code, parameter "type" should be set as "text/html",
281 * otherwise (if it is set as "text/plain") html code is processed as a plain
282 * text. This method can be performed only once.<BR>
283 * <BR>
284 * In case of html content, it is essential to (on appropriate way) associate some
285 * attributes of particular elements in html code ("background" or "src" atributes)
286 * with corresponding ressources (URL-s, relative file addresses or byte array
287 * streams). This resources should all be sent with message to enable recipient
288 * to see complete html message. Location of resources can be given in few
289 * different forms and depending on that, allocation resolving can be successful or
290 * not. Following text represents different possibilities for defining locations
291 * of resources (pictures, animations, sound...) inside of html code passed to
292 * this method, and necessery passed additional parameters used for resolving
293 * this resource locations.<BR>
294 * <BR>
295 * <UL>
296 * <LI>URL defined as: http://... is left unchanged. This resource is not sent
297 * with the message and it couldn't be seen by recipient if it is not online on
298 * the internet.</LI>
299 * <LI>URL defined as: file://... is transformed to corresponding Content ID if
300 * the resource can be found on specified location and it is sent with message.</LI>
301 * <LI>Absolute path, for example defined as: "c:\tmp\test\picture.bmp", is
302 * transformed to corresponding Content ID if the resource can be found on
303 * specified location, and is sent with message. If all resources in html
304 * code are specified with its absolute path, the 3rd parameter in this method
305 * can be null.</LI>
306 * <LI>Relative path of all resources specified in html code, for example
307 * defined as: ".\test\picture.bmp" and ".\example\flush.swf", must be defined
308 * to be relative to same directory path (in this case it is c:\tmp). This parameter
309 * (common directory path) is given as 3rd parameter in this method, and is named
310 * "path". If html code is obtained from .html file, necessery common directory
311 * path is usually path to this .html file. Location of resource is transformed
312 * to corresponding Content ID if the resource can be found on specified location.
313 * This location is sent with the message.</LI>
314 * <LI>Byte array stream as resource for html attribute must be referenced from
315 * html code as: <BR>
316 * <BR><PRE>
317 * *****nnn<virtual_file_name><BR>
318 * <BR></PRE>
319 * Five '*' characters (must be five) define that it is resource expected from
320 * the stream. Other three characters must be digits (000-999) and represent
321 * index of corresponding stream in stream array. virtual_file_name is name and
322 * extension assigned to data passed from stream. Name is used in construction of
323 * "name" parameter in Content-Type, while extension of file name is used in
324 * detection of appropriate mime-type. Lenght of virtual_file_name is not
325 * important. If there is no data referenced from byte array stream ,4th
326 * parameter of this method named "resources" can be null. Also, if all resources
327 * are passed through the array of streams, 3th parameter ("path") can be null.
328 * Location of resource is transformed to corresponding Content ID if no error
329 * has occured during the process of allocation.</LI>
330 * </UL>
331 * <BR>
332 * All mentioned resource allocation types can be combined together in the same
333 * html code, and all will be processed with appropriate use of this method.<BR>
334 * <BR>
335 * Note that number of resource references that are defined in html code by
336 * using virtual_file_names must be greater than or equal to number of elements
337 * in array of InputStream (4th parameter). If one resource (one element in array
338 * of IputStream) is used in html code more than once, it is advisable to use
339 * same virtual_file_name in html code because message is then sent with only
340 * one attached resource (image, movie...). It is essetntial that desired resource
341 * in input stream array corresponds to specified "nnn" part of virtual_file_name.<BR>
342 * <BR>
343 * If resources specified on any described name can not be found or resolved,
344 * or if any exception has occured during its processing, they won't be added and
345 * html message will be sent withouth them.
346 * @param content String representation of message content (text or html code).
347 * @param type type of given content. It can take values: "text/plain" or
348 * "text/html".
349 * @param path common directory path for relative file locations in html code.
350 * It can be null if all resources set absolute path or are defined by
351 * byte array streams, or if sending resources with relative address it is not desired.
352 * Also, it is set to null in case of text/plain message.
353 * @param resources way for representing resources used in the given html code
354 * which will be added to message as array of InputStream. Detail use
355 * of this argument is described above. It can be null if no resources as byte
356 * array stream are used, or if sending resources given in that way is not desired.
357 * Also, it is set to null in case of text/plain message.
358 * @exception SMIMEException if content is tried to be added twice, or in case of
359 * wrong "type" parameter. Also, it can be caused by non SMIMEException which can
360 * be one of the following: MessagingException UnsoportedEncodingException.
361 */
362 public void setContent(String content, String type, String path,
363 InputStream[] resources) throws SMIMEException {
364
365 if (content != null) {
366 ByteArrayInputStream bais = null;
367
368 try {
369 bais = new ByteArrayInputStream(content.getBytes("ISO-8859-1"));
370 } catch (Exception e) {
371 throw SMIMEException.getInstance(this, e, "setContent");
372 }
373 this.setContent(bais, type, path, resources);
374
375 } else
376 throw new SMIMEException(this, 1035);
377 }
378
379 /***
380 * Sets message content from InputStream. This method can be performed only once.
381 * Message content can be given in two differrent forms: text and html code. If
382 * content is type of text, parameter "type" should be "text/plain", while if
383 * content is type of html code, parameter "type" should be set as "html/code".
384 * For further information refer to setContent method with four arguments
385 * (String, String, String, InputStream[] ) which is called by this method.
386 * @param content message content data given from any InputStream.
387 * Data can be text or html code and will be interpreted according to second
388 * parameter: "type".
389 * @param type type of given content. It can take values: "text/plain" or
390 * "text/html".
391 * @param path common directory path for relative file locations in html code.
392 * It can be null if all resources in html code have set absolute path or are
393 * defined by byte array streams, or if sending resources with relative address
394 * is not desired. Also, it is set to null in case of text/plain message.
395 * @param resources way for representing resources used in the given html code
396 * which will be added to message as array of InputStreams. Detail use
397 * of this argument is described in other setContent methods mentioned before.
398 * It can be null if no resources as byte array stream are used, or if sending
399 * resources given in that way is not desired. Also, it is set to null in case
400 * of text/plain message.
401 * @exception SMIMEException if content is tried to be added twice , in case of
402 * wrong "type" parameter or in case when parameter content is null. Also, it can
403 * be caused by non SMIMEException which is MessagingException.
404 */
405 public void setContent(InputStream content, String type, String path,
406 InputStream[] resources) throws SMIMEException {
407 if (textContentPresence)
408 throw new SMIMEException(this, 1049);
409 if (content != null) {
410 try {
411 if (type.equalsIgnoreCase("text/plain")) {
412 MimeBodyPart mbp = new MimeBodyPart();
413 String temp = new String(ConvertAssist.inStreamToByteArray(content), "ISO-8859-1");
414
415 mbp.setText(temp, "ISO-8859-1");
416 bodyPartArray.add(0, mbp);
417 textContentPresence = true;
418 } else if (type.equalsIgnoreCase("text/html")) {
419 MimeMultipart htmlMultipart =
420 MultipartGenerator.getHtmlMultipart(content, path, resources);
421
422 bodyPartArray.add(0, htmlMultipart);
423 textContentPresence = true;
424 } else
425 throw new SMIMEException(this, 1048);
426 } catch (Exception e) {
427 throw SMIMEException.getInstance(this, e, "setContent");
428 }
429 } else
430 throw new SMIMEException(this, 1035);
431 }
432
433 /***
434 * Sets message content from InputStream. This method can be performed only once.
435 * Message content can be given in two differrent forms: text and html code. If
436 * content is type of text, parameter "type" should be "text/plain", while if
437 * content is type of html code, parameter "type" should be set as "html/code".
438 * If html code content is set by this method, message will be generated withouth
439 * inclusion of the resources defined in paricular html element's attribute ("src" and
440 * "background"). Only plain html code will be sent and any reference to local
441 * file system resources will be useless for recipient of the message. HTTP referenced
442 * resources can still be available if recipient is online on Internet. Message
443 * generated on this way is smaller so encrypting process should be faster.
444 * @param content message content data given from any InputStream.
445 * Data could be text or html code and will be interpreted according to second
446 * parameter: "type".
447 * @param type type of given content. It can take values: "text/plain" or
448 * "text/html".
449 * @exception SMIMEException if content is tried to be added twice , in case of
450 * wrong "type" parameter or in case when parameter content is null. Also, it can
451 * be caused by non SMIMEException which is MessagingException.
452 */
453 public void setContent(InputStream content, String type) throws SMIMEException {
454 if (textContentPresence)
455 throw new SMIMEException(this, 1049);
456 if (content != null) {
457 try {
458 if (type.equalsIgnoreCase("text/plain")) {
459 MimeBodyPart mbp = new MimeBodyPart();
460 String temp = new String(ConvertAssist.inStreamToByteArray(content), "ISO-8859-1");
461
462 mbp.setText(temp, "ISO-8859-1");
463 bodyPartArray.add(0, mbp);
464 textContentPresence = true;
465 } else if (type.equalsIgnoreCase("text/html")) {
466 MimeMultipart htmlMultipart =
467 MultipartGenerator.getHtmlMultipart(content);
468
469 bodyPartArray.add(0, htmlMultipart);
470 textContentPresence = true;
471 } else
472 throw new SMIMEException(this, 1048);
473 } catch (Exception e) {
474 throw SMIMEException.getInstance(this, e, "setContent");
475 }
476 } else
477 throw new SMIMEException(this, 1035);
478 }
479
480 /***
481 * Sets message content from String. This method can be performed only once.
482 * Message content can be given in two differrent forms: text and html code. If
483 * content is type of text, parameter "type" should be "text/plain", while if
484 * content is type of html code, parameter "type" should be set as "html/code".
485 * If html code content is set by this method, message will be generated withouth
486 * inclusion of the resources defined in paricular html element's attribute ("src" or
487 * "background"). Only plain html code will be sent and any reference to local
488 * file system resources will be useless for recipient of the message. HTTP referenced
489 * resources can still be available if recipient is online on Internet. Message
490 * generated on this way is smaller, so encrypting process should be faster.
491 * @param content message content data given as String which can
492 * be text or html code and will be interpreted according to second parameter:
493 * "type".
494 * @param type type of given content. It can take values: "text/plain" or
495 * "text/html".
496 * @exception SMIMEException if content is tried to be added twice, or in case of
497 * wrong "type" parameter. Also, it can be caused by non SMIMEException which can
498 * be one of the following: MessagingException UnsoportedEncodingException.
499 */
500 public void setContent(String content, String type) throws SMIMEException {
501
502 if (content != null) {
503 ByteArrayInputStream bais = null;
504
505 try {
506 bais = new ByteArrayInputStream(content.getBytes("ISO-8859-1"));
507 } catch (Exception e) {
508 throw SMIMEException.getInstance(this, e, "setContent");
509 }
510 this.setContent(bais, type);
511
512 } else
513 throw new SMIMEException(this, 1035);
514 }
515
516 /***
517 * Sets message content from file represented by File object. This method can be
518 * performed only once. Message content can be given in two differrent forms:
519 * text and html code. If content is type of text, parameter "type" should be
520 * "text/plain", while if content is type of html code, parameter "type" should
521 * be set as "html/code". For further information refer to setContent method
522 * with four arguments (String, String, String, InputStream[] ) which is called
523 * by this method.
524 * @param inFile location of file which is used for content of the message
525 * @param type type of given content. It can take values: "text/plain" or
526 * "text/html".
527 * @exception SMIMEException if content is tried to be added twice, in case of
528 * wrong "type" parameter, or if passed file (as File object) does not exist in
529 * file sistem. Also, it can be caused by non SMIMEException which can be one of
530 * the following: MessagingException or IOException.
531 */
532 public void setContent(File inFile, String type) throws SMIMEException {
533
534 if (textContentPresence)
535 throw new SMIMEException(this, 1049);
536 if (inFile != null && inFile.exists()) {
537 try {
538 File inFileAbs = inFile.getAbsoluteFile().getCanonicalFile();
539 String content = ConvertAssist.readFileToString(inFileAbs);
540
541 this.setContent(content, type, inFile.getParent(), null);
542 } catch (Exception e) {
543 throw SMIMEException.getInstance(this, e, "setContent");
544 }
545 } else
546 throw new SMIMEException(this, 1034);
547 }
548
549 /***
550 * Sets REPLY TO field in message header
551 * @param replyAddress email address used for reply
552 * @exception SMIMEException caused by non SMIMEException which is
553 * MessagingException. Also javax.mail.internet.AddressException is thrown
554 * from instances of InternetAddress class (but AddressException extends
555 * MessagingException).
556 */
557 public void setReply(String replyAddress) throws SMIMEException {
558 try {
559 InternetAddress reply[] = new InternetAddress[1];
560
561 reply[0] = new InternetAddress(replyAddress);
562 message.setReplyTo(reply);
563 } catch (Exception e) {
564 throw SMIMEException.getInstance(this, e, "addRecipient");
565 }
566 }
567
568 /***
569 * Adds recipient address, type and .cer file of email recipient.
570 * @param recipientAddress email address of recipent (fields TO or CC or BCC
571 * in email message header)
572 * @param type should be TO, CC or BCC.
573 * @exception SMIMEException if type of addressing of the messages is not TO, CC,
574 * or BCC.
575 * @exception SMIMEException caused by non SMIMEException which is
576 * MessagingException.
577 */
578 public void addRecipient(String recipientAddress, String type) throws SMIMEException {
579 try {
580 if (!type.equalsIgnoreCase("TO") & !type.equalsIgnoreCase("BCC") & !type.equalsIgnoreCase("CC"))
581 throw new SMIMEException(this, 1042);
582 if (type.equalsIgnoreCase("TO")) {
583 message.addRecipients(Message.RecipientType.TO, recipientAddress);
584 indicatorTo = true;
585 } else if (type.equalsIgnoreCase("CC"))
586 message.addRecipients(Message.RecipientType.CC, recipientAddress);
587 else if (type.equalsIgnoreCase("BCC"))
588 message.addRecipients(Message.RecipientType.BCC, recipientAddress);
589 } catch (Exception e) {
590 throw SMIMEException.getInstance(this, e, "addRecipient");
591 }
592
593 }
594
595 /***
596 * Adds file as attachment to email message
597 * @param fileName path and file name used for attachment
598 * @exception SMIMEException if passed file (as File object) does not exist in
599 * file sistem. Also, it can be caused by non SMIMEException which is
600 * MessagingException
601 */
602 public void addAttachment(String fileName) throws SMIMEException {
603 File fn = new File(fileName);
604
605 this.addAttachment(fn);
606 }
607
608 /***
609 * Adds file as attachment to email message
610 * @param file used for attachment represented as File object
611 * @exception SMIMEException if passed file (as File object) does not exist in
612 * file sistem. Also, it can be caused by non SMIMEException which is
613 * MessagingException
614 */
615 public void addAttachment(File file) throws SMIMEException {
616 if (!file.exists())
617 throw new SMIMEException(this, 1034);
618 MimeBodyPart attachment = new MimeBodyPart();
619 FileDataSource fd = new FileDataSource(file);
620
621 try {
622 attachment.setDataHandler(new DataHandler(fd));
623 attachment.setDisposition(attachment.ATTACHMENT);
624 attachment.setFileName(file.getName());
625 } catch (Exception e) {
626 throw SMIMEException.getInstance(this, e, "addAttachment");
627 }
628
629 bodyPartArray.addElement(attachment);
630 }
631
632 /***
633 * Adds data from InputStream as attachment to email message
634 * @param data byte array from InputStream
635 * @param fileName virtual or real file name (wihouth path). Correct information
636 * about name; extension of file name is especially important. Name
637 * is used in construction of "name" parameter in Content-Type header line of
638 * body parts of mime message. Extension of file is used in detection of
639 * appropriate mime-type.
640 * @exception SMIMEException caused by non SMIMEException which is
641 * MessagingException
642 */
643 public void addAttachment(InputStream data, String fileName) throws SMIMEException {
644 MimeBodyPart attachment = new MimeBodyPart();
645
646 try {
647 attachment.setDataHandler(new DataHandler(new StreamDataSource(data, fileName)));
648 attachment.setDisposition(attachment.ATTACHMENT);
649 attachment.setFileName(fileName);
650 bodyPartArray.addElement(attachment);
651 } catch (Exception e) {
652 throw SMIMEException.getInstance(this, e, "addAttachment");
653 }
654 }
655
656 /***
657 * Sets Capabilities Attributes (method is optional, but if exists, must be
658 * performed before addSigner method). Depending on parameter type0, other five
659 * parameters make order in specific group of algorithms. Groups of algorithms
660 * with positions of specific algorithms are:<BR>
661 * (SIGNATURE, MD2 with RSA, MD5 with RSA, SHA1 with RSA, SHA1 with DSA, Unused field)<BR>
662 * (SYMMETRIC, RC2 40 bits, RC2 64 bits, RC2 128 bits, DES, DES_EDE3)<BR>
663 * (ENCIPHER, RSA, Unused field, Unused field, Unused field, Unused field)<BR>
664 * <BR>
665 * For example, if we wish to set Capabilities Attributes for symmetric algorithms
666 * in order: RC2 64 bits, RC2 40 bits and DES, encipher algorithm RSA (only possible
667 * in this version), and signature algorithms in order: SHA1 with RSA, MD5 with RSA
668 * and MD2 with RSA, we should make following lines of code<BR>
669 * <BR>
670 * setCapabilities ("SYMMETRIC", 2, 1, 0, 3, 0)<BR>
671 * setCapabilities ("ENCIPHER", 1, 0, 0, 0, 0)<BR>
672 * setCapabilities ("SIGNATURE", 3, 2, 1, 0, 0)<BR>
673 * <BR>
674 * 0 means exclusion of algorithm from the specified position in the method. It is
675 * free to decide which algorithm will be included, or which group of algorithm
676 * will be included in Capabilities Attributes. If no groups are added, capabilities
677 * attributes won't be added to Signed Attributes. If two or more signers will
678 * sign the message, and their capabilities are different, this method should
679 * be performed before every signing if we wish to specify Capabilities
680 * Attributes for all particular signers. If type0 parameter is set as:<BR>
681 * setCapabilities ("DEFAULT", 0, 0, 0, 0, 0)<BR>
682 * it is equivalent to:<BR>
683 * setCapabilities ("SYMMETRIC", 1, 0, 0, 0, 0)<BR>
684 * setCapabilities ("ENCIPHER", 0, 0, 1, 0, 0)<BR>
685 * setCapabilities ("SIGNATURE", 1, 0, 0, 0, 0)<BR>
686 * @param type0 sets group of algorithms for capabilities attributes. It can be set
687 * with values: SIGNATURE, SYMMETRIC, ENCIPHER or DEFAULT.
688 * @param par10 sets order in group of parameters, or exclude some algorithms
689 * from capabilities atributes. Can take values 1, 2, 3, 4 or 5 and 0 for
690 * exclusion of the particular algorithm.
691 * @param par20 same as for par10
692 * @param par30 same as for par10
693 * @param par40 same as for par10
694 * @param par50 same as for par10
695 * @exception SMIMEException if method is performed more than three times for one signer,
696 * or in case of wrong values of parameters.
697 */
698 public void setCapabilities(String type0, int par10, int par20, int par30,
699 int par40, int par50) throws SMIMEException {
700 int[] tempType = { par10, par20, par30, par40, par50 };
701
702 capabilitiesTemp.addElement(type0);
703 capabilitiesTemp.addElement(tempType);
704 if (capabilitiesTemp.size() > 6)
705 throw new SMIMEException(this, 1045);
706 }
707
708 /***
709 * Adds signer to signed S/MIME message
710 * @param pfxfileName path and file name with certificate and private key
711 * corresponding to the sender of the message (file with .p12 or .pfx extension)
712 * @param password used to access to .pfx or .p12 file
713 * @param signingAlg algorithm used for signing (can be SHA1_WITH_RSA,
714 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA).
715 * @param includingCert including/not including certificates to signed
716 * message
717 * @param includingSignAttrib including/not including signed attributes
718 * to signed message. Must be set to true in case of implicit signing
719 * @exception SMIMEException caused by non SMIMEException which can be one of the
720 * following: FileNotFoundException, NoSuchProviderException, KeyStoreException
721 * CertificateException, NoSuchAlgorithmException or IOException.
722 */
723 public void addSigner(String pfxfileName, String password, String signingAlg,
724 boolean includingCert, boolean includingSignAttrib) throws SMIMEException {
725 try {
726 char[] paswCh = password.toCharArray();
727 FileInputStream inPFX = new FileInputStream(pfxfileName);
728 KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
729
730 ks.load(inPFX, paswCh);
731 inPFX.close();
732 boolean[] incl = { includingCert, includingSignAttrib };
733
734 ksArray.addElement(ks);
735 digestArray.addElement(signingAlg);
736 including.addElement(incl);
737 if (capabilitiesTemp.size() != 0) {
738 for (int i = 0; i != capabilitiesTemp.size(); i++)
739 capabilities.addElement(capabilitiesTemp.elementAt(i));
740 }
741 for (int i = 0; i != (6 - capabilitiesTemp.size()); i++)
742 capabilities.addElement(null);
743 capabilitiesTemp = new Vector(0, 1);
744 } catch (Exception e) {
745 throw SMIMEException.getInstance(this, e, "addSigner");
746 }
747 }
748
749 /***
750 * Adds signer to signed S/MIME message
751 * @param chain certificate chain. First certificate in array must be
752 * owner's certificate, and last certificate has to be root certificate
753 * @param privKey private key corresponding to owner's certificate (DSA
754 * or RSA depend on type of signing)
755 * @param signingAlg algorithm used for signing (can be SHA1_WITH_RSA,
756 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA).
757 * @param includingCert including/not including certificates to signed
758 * message
759 * @param includingSignAttrib including/not including signed attributes
760 * to signed message. Must be set to true in case implicit signing
761 */
762 public void addSigner(X509Certificate[] chain, PrivateKey privKey,
763 String signingAlg, boolean includingCert, boolean includingSignAttrib) {
764 boolean[] incl = { includingCert, includingSignAttrib };
765
766 certChainArray.addElement(chain);
767 privKeyArray.addElement(privKey);
768 digestArray2.addElement(signingAlg);
769 including2.addElement(incl);
770 if (capabilitiesTemp.size() != 0) {
771 for (int i = 0; i != capabilitiesTemp.size(); i++)
772 capabilities2.addElement(capabilitiesTemp.elementAt(i));
773 }
774 for (int i = 0; i != (6 - capabilitiesTemp.size()); i++)
775 capabilities2.addElement(null);
776 capabilitiesTemp = new Vector(0, 1);
777 }
778
779 /***
780 * Adds additional certificate to signed message.
781 * @param cert X509 certificate.
782 */
783 public void addCertificate(X509Certificate cert) {
784 aditionalCerts.addElement(cert);
785 }
786
787 /***
788 * Creates and signes the message with default implicit signing.
789 * @exception SMIMEException if one of recipients is not declared as TO
790 * recipient, or if there is no message for signing. Also, it can be caused
791 * by non SMIMEException which can be one of the following: MessagingException
792 * or IOException.
793 */
794 public void signing() throws SMIMEException {
795 this.signing(false);
796 }
797
798 /***
799 * Creates and signes the message
800 * @param externalSignature choice between implicit and explicit signing
801 * (true = explicit or external signing, false = implicit or internal signing).
802 * @exception SMIMEException if one of recipients is not declared as TO
803 * recipient, or if there is no message for signing. Also, it can be caused
804 * by non SMIMEException which can be one of the following: MessagingException,
805 * or IOException.
806 */
807 public void signing(boolean externalSignature) throws SMIMEException {
808 try {
809 if (indicatorTo != true)
810 throw new SMIMEException(this, 1043);
811 if (textContentPresence & bodyPartArray.size() == 1) { // message contains only content
812 if (bodyPartArray.elementAt(0) instanceof MimeBodyPart) { // text/plain message
813 MimeBodyPart contentBody = (MimeBodyPart) bodyPartArray.elementAt(0);
814
815 message.setContent((String) contentBody.getContent(), contentBody.getContentType());
816 message.setDisposition(message.INLINE);
817 } else // text/html message
818 message.setContent((MimeMultipart) bodyPartArray.elementAt(0));
819 } else if (bodyPartArray.size() != 0) {
820 Multipart mp = new MimeMultipart();
821
822 for (int i = 0; i != bodyPartArray.size(); i++) {
823 if (bodyPartArray.elementAt(i) instanceof MimeMultipart) {
824 MimeBodyPart forMulti = new MimeBodyPart();
825
826 forMulti.setContent((MimeMultipart) bodyPartArray.elementAt(i));
827 mp.addBodyPart(forMulti);
828 } else
829 mp.addBodyPart((MimeBodyPart) bodyPartArray.elementAt(i));
830 }
831 message.setContent(mp);
832 } else
833 throw new SMIMEException(this, 1044);
834
835 CMSSignedDataSource ss = new CMSSignedDataSource(message, externalSignature);
836
837 for (int i = 0; i < ksArray.size(); i++) {
838 boolean[] incl = (boolean[]) including.elementAt(i);
839
840 for (int j = 6 * i; j != (6 * (i + 1)) && capabilities.elementAt(j) != null; j = j + 2) {
841 int[] capabil = (int[]) capabilities.elementAt(j + 1);
842
843 ss.setCapabilities((String) capabilities.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
844 }
845 ss.addSigner((KeyStore) ksArray.elementAt(i), incl[0], incl[1], (String) digestArray.elementAt(i));
846 }
847 for (int i = 0; i < certChainArray.size(); i++) {
848 boolean[] incl2 = (boolean[]) including2.elementAt(i);
849
850 for (int j = 6 * i; j != (6 * (i + 1)) && capabilities2.elementAt(j) != null; j = j + 2) {
851 int[] capabil = (int[]) capabilities2.elementAt(j + 1);
852
853 ss.setCapabilities((String) capabilities2.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
854 }
855 ss.addSigner((X509Certificate[]) certChainArray.elementAt(i), (PrivateKey) privKeyArray.elementAt(i), incl2[0], incl2[1], (String) digestArray2.elementAt(i));
856 }
857 for (int i = 0; i < aditionalCerts.size(); i++) {
858 ss.addCertificate((X509Certificate) aditionalCerts.elementAt(i));
859 }
860 message.setDataHandler(new DataHandler(ss));
861 HeadersUtil.updateHeaders(message);
862 message.setDescription("Signed SMIME message.");
863 message.setDisposition(message.ATTACHMENT);
864 SimpleTimeZone tz = (SimpleTimeZone) SimpleTimeZone.getDefault(); // Sets date and time
865 GregorianCalendar cal = new GregorianCalendar(tz);
866
867 message.setSentDate(cal.getTime());
868
869 clean();
870 } catch (Exception e) {
871 throw SMIMEException.getInstance(this, e, "signing");
872 }
873
874 }
875
876 /***
877 * Returns SMIME Message
878 * @return Signed S/MIME message
879 */
880 public MimeMessage getSignedMessage() {
881 return message;
882 }
883
884 /***
885 * Sends S/MIME message to SMTP host
886 * @exception MessagingException caused by use of methods from objects of class
887 * Transport.
888 */
889 public void send() throws MessagingException {
890 Transport.send(message);
891 }
892
893 /***
894 * Releases unnecessary memory
895 */
896 private void clean() {
897 ksArray = null;
898 digestArray = null;
899 including = null;
900 certChainArray = null;
901 privKeyArray = null;
902 digestArray2 = null;
903 including2 = null;
904 bodyPartArray = null;
905 aditionalCerts = null;
906 capabilitiesTemp = null;
907 capabilities = null;
908 capabilities2 = null;
909 System.gc(); // Calling garbage collector
910 }
911 }
912
This page was automatically generated by Maven